package com.example.securitydemo.configuration.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:8081"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",configuration);
        return source;
    }

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private CorsConfigurationSource corsConfigurationSource;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // httpBasic这个不要开，开了过后会默认加上BasicAuthenticationFilter。
                // 这个Filter会在Header中加入Authentication字段(如果走页面访问接口)，这个字段是账号密码的Base64编码。
//          .httpBasic()
//                .formLogin()
//                .loginPage("/login.html") // 登录页
//                .loginProcessingUrl("/user/login") //登录接口
                // 1.如果之前是被拦截跳到登录页的，则登录成功会回跳到被拦截页 ↓↓↓
                // 2.如果是直接进入的登录页，则登录成功会跳转到该默认登录成功页面) ↓↓↓
//                .defaultSuccessUrl("/defaultSuccess.html") // 默认登录成功跳转页
//                .successForwardUrl("/success.html") //登录成功请求转发的url(连带登录方法的请求方式) 这个方法是个坑
//                .failureForwardUrl("/failure.html") //失败转发url
//                .permitAll() //以上Form表单登录的部分被允许所有权限的人
        .csrf().disable() // 关闭csrf 防护 csrf开启需要附加_csrf_token
        .logout().logoutUrl("/logout").clearAuthentication(true)
        .and().exceptionHandling().accessDeniedPage("/accessDenied.html")// 设置403访问页面
        .and().authorizeRequests()
                .antMatchers("/hasAuth1/**").hasAuthority("admin")
                .antMatchers("/hasAuth2/**").hasAnyAuthority("ad")
                .antMatchers("/hasRole1").hasRole("sp")
                .antMatchers("/hasRole2").hasAnyRole("st")
                .anyRequest().authenticated() // any的意思是除了antMatcher部分之外的所有需要授权的请求必须要被认证过。
        .and().cors().configurationSource(corsConfigurationSource) //打开cors
        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).disable() //关闭Session
            .addFilterAt(new TokenLoginFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
            .addFilterAt(new TokenAuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class)
            ;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 设置忽略需要权限的
        web.ignoring().antMatchers("/dev/**");
    }

}
